<?php

  require_once 'PHPUnit/Framework.php';
  require_once 'PHPUnit/Framework/IncompleteTestError.php';
  require_once 'PHPUnit/Framework/TestCase.php';
  require_once 'PHPUnit/Framework/TestSuite.php';
  require_once 'PHPUnit/Runner/Version.php';
  require_once 'PHPUnit/TextUI/TestRunner.php';
  require_once 'PHPUnit/Util/Filter.php';

  require_once 'Zend/Debug.php';

  require_once 'JooS/Helper/Abstract.php';
  require_once 'JooS/Helper/Broker.php';
  require_once 'JooS/PHPUnit/TestCase.php';

  JooS_Helper_Broker::addPrefix("PHPUnit");

  class JooS_PHPUnit_AllTests {
    const iniFileName = "AllTests.ini";

    public static function main($suite, $arguments = null) {
      ini_set("display_errors", 1);
      error_reporting( E_ALL | E_STRICT );

      if (!$arguments || !is_array($arguments))
        $arguments = array(
          'verbose' => true
        );

      if ($suite = self::suite($suite))
        PHPUnit_TextUI_TestRunner::run($suite, $arguments );
    }

    public static function requireTests($addTest = array(), $addTestSuite = array(), $arguments = null) {
      self::main(array(
        "addTest" => $addTest, 
        "addTestSuite" => $addTestSuite, 
      ), $arguments);
    }
        
    private static $includePaths = null;

    private static function getIncludePaths() {
      if (null === self::$includePaths) {
        self::$includePaths = explode(PATH_SEPARATOR, get_include_path());
      }
      return self::$includePaths;
    }
    
    private static function getAllTests($suiteClass) {
      require_once 'Zend/Config/Ini.php';

      $suitePath = str_replace("_", DIRECTORY_SEPARATOR, $suiteClass);
      $paths = self::getIncludePaths();

      $Ini = null;
      foreach ($paths as $path) {
        $iniFileName = $path . DIRECTORY_SEPARATOR . ($suitePath ? $suitePath . DIRECTORY_SEPARATOR : "") . self::iniFileName;
        if (file_exists($iniFileName)) {
          $Ini = new Zend_Config_Ini($iniFileName);
          break;
        }
      }
      if ($Ini) {
        if ($Ini->AllTests instanceOf Zend_Config) {
          $AllTests = $Ini->AllTests->toArray();

          if (!isset($AllTests["addTestSuite"]) || !is_array($AllTests["addTestSuite"]))
            $AllTests["addTestSuite"] = array();
          
          if (!isset($AllTests["addTest"]) || !is_array($AllTests["addTest"]))
            $AllTests["addTest"] = array();

          return $AllTests;
        }
        else
          throw new Exception(self::iniFileName . " for '$suiteClass' must contain [AllTests] section");
      }
      else
        throw new Exception(self::iniFileName . " for '$suiteClass' not found");
    }
    
    private static $_addedTestSuites = array();
    private static $_addedTests = array();
    
    private static function createPHPUnitTestSuite($title) {
      return new PHPUnit_Framework_TestSuite($title);
    }

    private static function addTestSuite(&$suite, $testSuite, $title) {
      if (!$suite)
        $suite = self::createPHPUnitTestSuite($title);
      $suite->addTestSuite($testSuite);
    }

    private static function addTest(&$suite, $test, $title) {
      if ($test) {
        if (!$suite)
          $suite = self::createPHPUnitTestSuite($title);
        $suite->addTest($test);
      }
    }
    
    private static function suite($suiteClass, $title = "") {
      $AllTests = is_array($suiteClass) ? $suiteClass : self::getAllTests($suiteClass);

      $title = ($title ? $title : (
        is_string($suiteClass) ?
        "[" . $suiteClass . "]." . self::iniFileName :
        (sizeof($suiteClass["addTest"]) ? "[Required Tests: " . implode(",", $suiteClass["addTest"]) . "]" : "").(sizeof($suiteClass["addTestSuite"]) ? "[Required testSuites: " . implode(",", $suiteClass["addTestSuite"]) . "]" : "")
      ));

      $suite = null;

      foreach ($AllTests["addTestSuite"] as $addTestSuite) {
        if (in_array($addTestSuite, self::$_addedTestSuites))
          continue;
        else
          self::$_addedTestSuites[] = $addTestSuite;

        $classPath = str_replace("_", DIRECTORY_SEPARATOR, $addTestSuite).".php";

        require_once($classPath);
        
        self::addTestSuite($suite, $addTestSuite, $title);
      }

      foreach ($AllTests["addTest"] as $addTest) {
        if (in_array($addTest, self::$_addedTests))
          continue;
        else
          self::$_addedTests[] = $addTest;

        self::addTest($suite, self::suite($addTest), $title);
      }

      return $suite;
    }
  }

?>